home *** CD-ROM | disk | FTP | other *** search
- /*
- * Auxiliary routines, all taken from xyplot (translated from Fortran to C).
- */
-
- #include "defs.h"
- #include <strings.h>
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h> /* for exit() */
- #include <appkit/Panel.h> /* for NXRunAlertPanel */
-
- /*
- * Count the number of labels on a given axis.
- */
- void
- count_labels(int *pn, double *pfirst, double min, double inc, double max)
- {
- int bottom, top, j;
- double range, absinc, tol, guess;
-
- if (inc != 0.0) {
- *pn = 0;
- bottom = (int)(min/inc) - 1;
- top = (int)(max/inc) + 1;
- range = ABS(max - min);
- absinc = MIN(range, ABS(inc));
- tol = absinc * (range + absinc) / 100.0;
- for (j=top; j>=bottom; j--) {
- guess = (double)j * inc;
- if ( (max-guess)*(guess-min) >= -tol) {
- *pn += 1;
- *pfirst = guess;
- }
- }
- }
- else {
- *pn = 0;
- *pfirst = 0.0;
- }
- return;
- }
-
- /*
- * Write a float into a string and see how many characters are to the left
- * of the decimal point, how many total decimal characters there are, and
- * how many characters there are in the exponent (if exponential notation).
- */
- void
- numstring(double x, int *nl, int *nd, int *ne)
- {
- char string[80];
- double ax;
- int i, nc, net;
-
- ax = ABS(x);
- i = ax;
- if ((double)i==ax && ax<99999.0) {
- sprintf(string, "%1d", (int)x);
- }
- else {
- if (ax>=1.e-4 && ax<1.e5) {
- if ( ((int)(x*10000.0) % 10000) == 0 )
- sprintf(string, "%-6.0f", x); /* left-justify */
- else if ( ((int)(x*10000.0) % 1000) == 0 )
- sprintf(string, "%-7.1f", x);
- else if ( ((int)(x*10000.0) % 100) == 0 )
- sprintf(string, "%-8.2f", x);
- else if ( ((int)(x*10000.0) % 10) == 0 )
- sprintf(string, "%-9.3f", x);
- else
- /* sprintf(string, "%-10.4f", x); this can fail -- e.g., x=0.000718 */
- sprintf(string, "%10.6f", x); /* will this always work? */
- }
- else {
- sprintf(string, "%-#11.2e", x);
- }
- }
- nc = strlen(string);
- /* strip off blanks from the end of the string: */
- while (string[nc-1] == ' ') {
- string[--nc] = '\0';
- }
- nc = strlen(string);
-
- /* nl = no. of characters left of the decimal point (including sign) */
- *nl = 0;
- for (i=nc-1; i>=0; i--) {
- *nl += 1;
- if (string[i] == '.') *nl = 0;
- }
-
- /* nd = no. of decimal characters (including decimal point, omitting
- * trailing zeros)
- */
- *nd = 0;
- for (i=nc-1; i>=*nl; i--) {
- *nd += 1;
- if (string[i] == 'e' || string[i] == 'E') *nd = 0;
- if (string[i] == '0' && *nd == 1) *nd = 0;
- }
-
- /* ne = no. of exponent characters (including the 'E' if any) */
- *ne = 0;
- for (i=*nl + *nd; i<nc; i++) {
- if (string[i] == 'e' || string[i] == 'E') *ne = nc - i;
- }
- net = 0;
- for (i = nc-1; i >= nc - *ne + 2; i--) {
- if (string[i] != '0') net = 2 + nc - i;
- }
- *ne = net;
-
- /* Some special cases where floating point numbers may be
- * expressed as integers.
- */
- if (*nd==1 && *ne==0) *nd = 1;
- return;
- }
-
- /*
- * See what the formatting would be if we go from min to max in
- * steps of inc.
- */
- void
- autoformat(double min, double inc, double max, int *axformat)
- {
- int nlabels, i, nl, nd, ne;
- double first, value;
-
- *axformat = 0;
- *(axformat + 1) = 0;
- *(axformat + 2) = 0;
- count_labels(&nlabels, &first, min, inc, max);
- for (i=0; i<nlabels; i++) {
- /* Special test here for what should be exact 0 (but isn't sometimes
- * due to floating-point arithmetic.
- */
- if (inc != 0.0 && fabs(first/inc + (double)i) < 1.0e-14) { /* ugly */
- value = 0.0;
- }
- else {
- value = first + inc*(double)i;
- }
- numstring(value, &nl, &nd, &ne);
- if (*(axformat+2)==0 && ne!=0) {
- *axformat = nl;
- *(axformat+1) = nd;
- *(axformat+2) = ne;
- }
- else {
- *axformat = MAX(nl, *axformat);
- *(axformat+1) = MAX(nd, *(axformat+1));
- *(axformat+2) = MAX(ne, *(axformat+2));
- }
- }
- return;
- }
-
- /*
- * Put a float into a string with a specified format.
- */
- void
- handformat(float number, char *string, int *axformat)
- {
- int nl, nd, ne;
-
- nl = *(axformat+0);
- nd = *(axformat+1);
- ne = *(axformat+2);
-
- // if all axformat[i] are 0, return just a blank:
- if (ne==0 && nd==0 && nl==0) {
- sprintf(string, " ");
- return;
- }
-
- // special case 0:
- if (number == 0.0) {
- sprintf(string, "%1d", 0);
- return;
- }
- if (ne==0) {
- if (nd==0) {
- sprintf(string, "%*d", nl, (int)rint((double)number));
- }
- else
- sprintf(string, "%*.*f", nl, nd-1, number);
- }
- else {
- if (nd==0)
- sprintf(string, "%*.*e", nl, nd, number);
- else
- sprintf(string, "%*.*e", ne+1, nd-1, number);
- }
- return;
- }
-
- /*
- * Compute nice increment for linear plotting, given min and max.
- */
- void
- computeNiceLinInc(float *pmin, float *pmax, float *pinc)
- {
- float fmin = *pmin, fmax = *pmax, finc = (fmax - fmin)/5.0, x;
- int n;
-
- if (finc <= 0.0) {
- fmin = (fmin>0.0? 0.9*fmin : 1.1*fmin);
- fmax = (fmax>0.0? 1.1*fmax : 0.9*fmax);
- finc = (fmax - fmin)/5.0;
- // for safety:
- if (finc < 0.0) {
- n = NXRunAlertPanel("computeNiceLinInc",
- "Impossible increment = %g.\n"
- "I'm very confused "
- "(Perhaps all data is being ignored -- no lines, no symbols)",
- "Quit", "Continue", NULL, finc);
- if (n==NX_ALERTDEFAULT)
- exit(0);
- else if (n==NX_ALERTALTERNATE) {
- *pmin = 0.0;
- *pmax = 1.0;
- *pinc = 0.2;
- return;
- }
- }
- }
- n = ( log10((double)finc) >= 0.0 ? (int)floor(log10((double)finc)) :
- (int)ceil(log10((double)finc)) );
- if (finc > 1.0) n++;
- x = finc * (float)pow((double)10.0, (double)(-n));
- finc = 0.1;
- if (x > 0.1) finc = 0.2;
- if (x > 0.2) finc = 0.25;
- if (x > 0.25) finc = 0.5;
- if (x > 0.5) finc = 1.0;
- finc = finc * (float)pow((double)10.0, (double)n);
-
- if (fmin < ((int)(fmin/finc))*finc) fmin = ((int)(fmin/finc - 1))*finc;
- else fmin = ((int)(fmin/finc))*finc;
-
- if (fmax > ((int)(fmax/finc))*finc) fmax = ((int)(fmax/finc + 1))*finc;
- else fmax = ((int)(fmax/finc))*finc;
-
- *pmin = fmin;
- *pmax = fmax;
- *pinc = finc;
- return;
- }
-
-
- /*
- * Compute a nice min and max for logarithmic plotting (we take increment=1).
- */
- void
- computeNiceLogInc(float *pmin, float *pmax, float *pinc)
- {
- float fmin, fmax, finc;
- int n;
-
- // for safety:
- if (*pmin <= 0.0 || *pmax <= 0.0) {
- n = NXRunAlertPanel("computeNiceLogInc",
- "Impossible min/max = %g, %g.\n"
- "I'm very confused "
- "(Perhaps all data is being ignored -- no lines, no symbols)",
- "Quit", "Continue", NULL, *pmin, *pmax);
- if (n==NX_ALERTDEFAULT)
- exit(0);
- else if (n==NX_ALERTALTERNATE) {
- *pmin = 1.0;
- *pmax = 10.0;
- *pinc = 1.0;
- return;
- }
- }
-
- fmin = (float)log10(*pmin);
- fmax = (float)log10(*pmax);
- finc = 1.0;
-
- fmin = (float) floor((double)fmin);
- fmax = (float) ceil((double)fmax);
-
- if (fmin == fmax) {
- fmin = fmin - 1.0;
- fmax = fmax + 1.0;
- }
- *pmin = (float)pow((double)10.0, (double)fmin);
- *pmax = (float)pow((double)10.0, (double)fmax);
- *pinc = (float)pow((double)10.0, (double)finc);
- return;
- }
-